package com.apes.scm.stock.inventory.service;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.apes.framework.api.DomainService;
import com.apes.framework.jpa.spec.JpaDsl;
import com.apes.framework.plugin.esb.api.SimpleRequest;
import com.apes.framework.util.MapUtil;
import com.apes.framework.util.Tools;
import com.apes.scm.masterdata.enumeration.model.Enumeration;
import com.apes.scm.masterdata.enumeration.repository.EnumerationRepository;
import com.apes.scm.masterdata.product.model.Product;
import com.apes.scm.masterdata.product.repository.ProductRepository;
import com.apes.scm.masterdata.product.repository.ServeCategoryRepository;
import com.apes.scm.rbac.model.Menu;
import com.apes.scm.stock.inventory.model.InventoryDiffCompound;
import com.apes.scm.stock.inventory.model.InventoryList;
import com.apes.scm.stock.inventory.model.InventoryListItem;
import com.apes.scm.stock.inventory.model.InventoryResolveRecord;
import com.apes.scm.stock.inventory.repository.InventoryDiffCompoundRepository;
import com.apes.scm.stock.inventory.repository.InventoryListRepository;
import com.apes.scm.stock.inventory.repository.InventoryResolveRecordRepository;
import org.apache.ibatis.javassist.expr.NewArray;
import org.hibernate.SQLQuery;
import org.hibernate.transform.Transformers;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;
import com.apes.framework.jpa.generator.service.SequenceService;
import org.springframework.util.StringUtils;

import javax.persistence.EntityManager;
import javax.persistence.Query;
import java.util.*;
import java.util.stream.Collectors;

@Service("inventoryListService")
public class InventoryListService extends DomainService {

    @Autowired
    private EntityManager entityManager;

    @Autowired
    private InventoryListRepository inventoryListRepository;

    @Autowired
    private ProductRepository productRepository;

    @Autowired
    private SequenceService sequenceService;

    @Autowired
    private InventoryResolveRecordRepository inventoryResolveRecordRepository;

    @Autowired
    private EnumerationRepository enumerationRepository;

    @Autowired
    private InventoryDiffCompoundRepository inventoryDiffCompoundRepository;

    /**
     * 保存
     *
     * @param request
     * @return
     */
    public InventoryList save(SimpleRequest request) {
        InventoryList inventoryList = request.getO(InventoryList.class);
        inventoryList.setCreateDate(new Date());
        inventoryList.setState("create");

        //不同明细存在相同商品，报错
        List<String> products = inventoryList.getInventoryListItem().stream().map(e -> e.getProductId().getId()).collect(Collectors.toList());
        long count = products.stream().distinct().count();
        if (inventoryList.getInventoryListItem().size() != count) throw new RuntimeException("盘点表明细");

        // 设置公司为仓库公司
        if (inventoryList.getCompany() == null) inventoryList.setCompany(inventoryList.getWarehouseId().getCompany());
        return inventoryListRepository.saveAndFlush(inventoryList);
    }

    /**
     * 录入盘点-----【盘点】
     *
     * @param request
     * @return
     */
    public InventoryList update(SimpleRequest request) {
        JSONObject inventoryJO = request.getJO();
        // 更新不直接用mapping,可能会误删原明细
        InventoryList inventoryList = inventoryListRepository.findOne(inventoryJO.getString("id"));
        if (inventoryList == null || "delete".equals(inventoryList.getState())) throw new RuntimeException("未找到有效盘点单");

        inventoryList.setState("inventory");
        inventoryList.setInventoryDate(new Date());

        // 配合扫码这里用商品编码作为key
        Map<String, InventoryListItem> itemsMap = inventoryList.getInventoryListItem().stream().
                collect(Collectors.toMap(InventoryListItem::acquireProductCode,
                        item -> item,
                        (oldValue, newValue) -> {
                            // 这里报错说明在创建盘点单的时候，就存在商品重复
                            throw new RuntimeException("商品重复！重复编码：" + newValue.getProductId().getId());
                        }));

        // 匹配更新盘点数量/找不到明细为新增
        JSONArray items = inventoryJO.getJSONArray("inventoryListItem");
        items.forEach((item) -> {
            JSONObject itemObj = (JSONObject) item;
            String productId = itemObj.getJSONObject("productId").getString("id");
            if (!itemsMap.containsKey(productId)) {
                InventoryListItem inventoryListItem = new InventoryListItem();
                inventoryListItem.setInventoryListId(inventoryList);

                //由于扫码端存在保存报错的问题，这里去掉设置 ID
//                inventoryListItem.setId(sequenceService.getId(InventoryListItem.CONST_TABLE_NAME));

                inventoryListItem.setProductId(productRepository.findOne(productId));
                if (inventoryListItem.getProductId() == null) throw new RuntimeException("找不到商品信息,商品编码错误！" + productId);

                inventoryListItem.setUnitId(inventoryListItem.getProductId().getUom());     // 计量单位
                inventoryListItem.setCountQuantity(itemObj.getDouble("countQuantity")); // 盘点数量
                inventoryList.getInventoryListItem().add(inventoryListItem);
            } else {
                InventoryListItem inventoryListItem = itemsMap.get(productId);
                if (inventoryListItem == null) throw new RuntimeException("未找到对应明细！");
                if (itemObj.getDouble("countQuantity") == 0) {
                    inventoryListItem.setCountQuantity(0);
                } else {
                    inventoryListItem.setCountQuantity(inventoryListItem.getCountQuantity() + itemObj.getDouble("countQuantity"));
                }
            }
        });

        return saveAndFlush(inventoryList);
    }

    /**
     * 删除
     *
     * @param request
     */
    public Map delete(SimpleRequest request) {
        InventoryList inventoryList = inventoryListRepository.findOne(request.get("id").toString());
        inventoryList.setState("delete");
        inventoryList.setDeleteDate(new Date());
        saveAndFlush(inventoryList);
        return new HashMap();

    }

    /**
     * 审核
     *
     * @param request
     * @return
     */
    public InventoryList approve(SimpleRequest request) {
        InventoryList inventoryList = request.getO(InventoryList.class);
        inventoryList.setState("approve");
        //String id = inventoryList.getId();
        // 筛选盘点数量与保管数量不一致明细
        Set<InventoryListItem> inventoryListItems = inventoryList.getInventoryListItem().stream().filter(
                (item) -> item.getCustodyQty() != item.getCountQuantity()
        ).collect(Collectors.toSet());
        // 没有差异更新为完成
        if (inventoryListItems.isEmpty()) inventoryList.setState("done");
        List<InventoryDiffCompound> compounds = new ArrayList<>();
        for (InventoryListItem item : inventoryListItems) {
            // 更新差异数量（盘亏数量）
            item.setProfitAndLoss(item.getCountQuantity() - item.getCustodyQty());
            InventoryDiffCompound inventoryDiffCompound = new InventoryDiffCompound();
            inventoryDiffCompound.setProductId(item.getProductId());
            inventoryDiffCompound.setUnitId(item.getUnitId());
            inventoryDiffCompound.setCustodyQty(item.getCustodyQty());
            inventoryDiffCompound.setInventoryListIds(inventoryList);
            inventoryDiffCompound.setFirstSetQty(item.getCountQuantity());
            // 初盘差异 = 盘点 - 保管 - 在途
            inventoryDiffCompound.setInitialDiscrepanciesQty(item.getCountQuantity() - item.getCustodyQty() - item.getInTransitQty());
            inventoryDiffCompound.setCompoundQty(0);
            inventoryDiffCompound.setComplexDifferenceQty(0);
            inventoryDiffCompound.setProcessedQty(0);
            inventoryDiffCompound.setCreateDate(new Date());
            // 在途数量
            inventoryDiffCompound.setInTransitQty(item.getInTransitQty());
            compounds.add(inventoryDiffCompound);
        }
        inventoryList.setInventoryDiffCompound(compounds);
        inventoryList = saveAndFlush(inventoryList);
        // sql 直接更新数据库表会让模型数据不一致
        // inventoryListItemRepository.updateInventoryListItem(id);
        //inventoryList.setInventoryListItem(inventoryListRepository.findOne(inventoryList.getId()).getInventoryListItem());
        //System.out.println(inventoryListRepository.findOne(inventoryList.getId()).getInventoryListItem());
        return inventoryList;
    }

    /**
     * 盘点差异复盘-----复盘
     *
     * @param request
     * @return
     */
    public InventoryList compound(SimpleRequest request) {
        InventoryList inventoryList = request.getO(InventoryList.class);
        inventoryList.setState("compound");
        inventoryList.setCompoundDate(new Date());
        return saveAndFlush(inventoryList);
    }


    /**
     * 编辑
     *
     * @param request
     * @return
     */
    public InventoryList editUpdate(SimpleRequest request) {
        InventoryList inventoryList = request.getO(InventoryList.class);
        inventoryList.setCompoundDate(new Date());
        return saveAndFlush(inventoryList);
    }


    /**
     * 盘点差异复盘 ----- 复审
     *
     * @param request
     * @return
     */
    public InventoryList review(SimpleRequest request) {
        InventoryList inventoryList = request.getO(InventoryList.class);
        inventoryList.setState("review");
        inventoryList.setReviewDate(new Date());
        // sql 直接更新数据库表会让模型数据不一致
        // String id = inventoryList.getId();
        // inventoryDiffCompoundRepository.updateInventoryDiffCompound(id);
        for (InventoryDiffCompound inventoryDiffCompound : inventoryList.getInventoryDiffCompound()) {
            // 复盘差异数量
            inventoryDiffCompound.setComplexDifferenceQty(inventoryDiffCompound.getCompoundQty() - inventoryDiffCompound.getCustodyQty());
        }
        inventoryList = saveAndFlush(inventoryList);
        return inventoryList;
    }

//    /**
//     * 查找具体某一条数据
//     * request.get("state") 录入盘点结果用到
//     *
//     * @param request
//     * @return
//     */
//    public InventoryList findOne(SimpleRequest request) {
//        String id = request.get("id");
//        InventoryList mainAndItem = inventoryListRepository.findOne(id);
//
//        if (mainAndItem == null || (mainAndItem != null && mainAndItem.getState().equals("delete"))) {
//            throw new RuntimeException("未找到相关数据！");
//        }
//        if (request.get("state").equals(1)) {
//            if (!mainAndItem.getState().equals("approve") && !mainAndItem.getState().equals("compound") && !mainAndItem.getState().equals("review")) {
//                throw new RuntimeException("未找到相关数据！");
//            }
//        }
//        return mainAndItem;
//    }


    /**
     * 查找商品库存
     *
     * @param request
     * @return
     */
    public List<InventoryListItem> findInventoryDetails(SimpleRequest request) {
        InventoryList inventoryList = request.getO(InventoryList.class);
        JSONObject model = request.get("model");
        Map<String, Object> params = new HashMap<>();
        List<InventoryListItem> resutlInventoryItem = new ArrayList<InventoryListItem>();
        if (!"".equals(model.getString("warehouseId")) && model.getString("warehouseId") != null) {
            StringBuffer stockItem_Buffer = new StringBuffer();
            stockItem_Buffer.append(" SELECT A.COMPANY_ID, A.LOCATION_ID, A.PRODUCT_ID, A.USABLE_QTY, ");
            stockItem_Buffer.append("        (A.TRANSFER_ISSUE_QTY + A.LEND_QTY) INTRANSIT_QTY,  ");
            stockItem_Buffer.append("        A.CUSTODY_QTY, B.NAME PRODUCT_NAME, B.PRODUCT_UOM_ID, ");
            stockItem_Buffer.append("        C.NAME PRODUCT_UOM_NAME ");
            stockItem_Buffer.append("   FROM ACC_STOCK A, MAS_PRODUCT B, MAS_PRODUCT_UOM C ");
            stockItem_Buffer.append("  WHERE A.PRODUCT_ID = B.ID AND B.PRODUCT_UOM_ID = C.ID ");
            stockItem_Buffer.append("    AND A.LOCATION_ID = :location");

            params.put("location", model.getJSONObject("warehouseId").getString("id"));
            if (StringUtils.hasText(model.getString("product")) && !"[]".equals(model.getString("product"))) {
                stockItem_Buffer.append(" AND B.ID in :product");
                List<String> products = model.getJSONArray("product").stream().map(o -> ((JSONObject) o).getString("id")
                ).collect(Collectors.toList());
                params.put("product", products);
            }
            if (StringUtils.hasText(model.getString("category")) && !"[]".equals(model.getString("category"))) {
                stockItem_Buffer.append(" AND B.CATEGORY_ID in :category");
                List<String> categories = model.getJSONArray("category").stream().map(o -> ((JSONObject) o).getString("id")
                ).collect(Collectors.toList());
                params.put("category", categories);
            }
            if (StringUtils.hasText(model.getString("classifyId")) && !"[]".equals(model.getString("classifyId"))) {
                stockItem_Buffer.append(" AND B.CLASSIFY_ID in :classify");
                List<String> classifyId = model.getJSONArray("classifyId").stream().map(o -> ((JSONObject) o).getString("id")
                ).collect(Collectors.toList());
                params.put("classify", classifyId);
            }
            if (StringUtils.hasText(model.getString("brand")) && !"[]".equals(model.getString("brand"))) {
                stockItem_Buffer.append(" AND B.BRAND_ID in :brand");
                List<String> brands = model.getJSONArray("brand").stream().map(o -> ((JSONObject) o).getString("id")
                ).collect(Collectors.toList());
                params.put("brand", brands);
            }
            if (StringUtils.hasText(model.getString("serveType")) && !"[]".equals(model.getString("serveType"))) {
                List<String> classifies = getBean(ServeCategoryRepository.class).findByClassify(model.getJSONObject("serveType").getString("id"));
                stockItem_Buffer.append(" AND B.CLASSIFY_ID in :serveType");
                params.put("serveType", classifies);
            }
            if (StringUtils.hasText(model.getString("productLike")) && !"[]".equals(model.getString("productLike"))) {
                String productLike = "%" + model.getString("productLike") + "%";
                stockItem_Buffer.append(" AND B.NAME like :productLike");
                params.put("productLike", productLike);
            }


            Query query = entityManager.createNativeQuery(stockItem_Buffer.toString());
            query.getParameters().stream().forEach(param -> {
                query.setParameter(param.getName(), params.get(param.getName()));
            });
            query.unwrap(SQLQuery.class).setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP);
            resutlInventoryItem = query.getResultList();
        }
        if (resutlInventoryItem.isEmpty()) throw new RuntimeException("库存盘点数量为0！");
        return resutlInventoryItem;
    }


    /***
     * 添加处理明细
     */

    public InventoryDiffCompound addResolveRecord(SimpleRequest request) {

        JSONObject tempJson = request.getJO();

        InventoryResolveRecord inventoryResolveRecord = new InventoryResolveRecord();
        //设置编码
        inventoryResolveRecord.setId(getBean(SequenceService.class).getId(InventoryResolveRecord.CONST_TABLE_NAME));


        inventoryResolveRecord.setInventorySourceType(enumerationRepository.findOne(tempJson.getJSONObject("inventorySourceType").getString("id")));

        inventoryResolveRecord.setSource(tempJson.getString("source"));
        inventoryResolveRecord.setQtyResolve(tempJson.getDoubleValue("qtyResolve"));
        inventoryResolveRecord.setRemark(tempJson.getString("remark"));

        // 删除字段
        tempJson.remove("inventorySourceType");
        tempJson.remove("source");
        tempJson.remove("qtyResolve");
        tempJson.remove("remark");
        tempJson.remove("inventoryResolveRecordList");
        request.setData(tempJson);
        InventoryDiffCompound inventoryDiffCompound = request.getO(InventoryDiffCompound.class);

        inventoryResolveRecord.setInventoryDiffCompound(inventoryDiffCompound);
        inventoryResolveRecordRepository.saveAndFlush(inventoryResolveRecord);

        // 设置处理数量
        InventoryList inventoryList = inventoryDiffCompound.getInventoryListIds();
        inventoryList.getInventoryDiffCompound().stream()
                .filter(inventoryDiffCompound1 -> inventoryDiffCompound1.getId().equals(inventoryDiffCompound.getId()))
                .forEach(inventoryDiffCompound1 -> inventoryDiffCompound1.addProcessedQty(inventoryResolveRecord.getQtyResolve()));

        inventoryList = inventoryListRepository.saveAndFlush(inventoryList);

        return inventoryList.getInventoryDiffCompound().stream()
                .filter(inventoryDiffCompound1 -> inventoryDiffCompound1.getId().equals(inventoryDiffCompound.getId())).findFirst().get();
    }

    public InventoryList saveAndFlush(InventoryList inventoryList) {
        return inventoryListRepository.saveAndFlush(inventoryList);
    }

    public InventoryList findInventoryListById(String id) {
        return inventoryListRepository.findOne(id);
    }

    public List<InventoryList> findInventoryListForPDA(String localtionId) {
        return inventoryListRepository.findInventoryListForPDA(localtionId);
    }

    /***
     * 导入数据解析接口
     * 导入盘点表
     */
    public Map beImportInventoryList(SimpleRequest request) {

        JSONObject importData = request.get("importData"); // excel数据
        JSONObject exclJson = new JSONObject(); //返回值

        JSONArray inventoryDiffCompoundJSONArray = request.getJO().getJSONObject("model").getJSONArray("inventoryListItem");
        List<InventoryListItem> inventoryLists = JSON.parseArray(inventoryDiffCompoundJSONArray.toString(), InventoryListItem.class);
        if (importData.keySet().size() != 1) {
            throw new RuntimeException("导入数据不存在或者存在多个工作表");
        }

        // 获取第一个工作表的数据
        String sheetName = (String) importData.keySet().toArray()[0];
        JSONArray array = importData.getJSONArray(sheetName);

        // 判断是否满足表头顺序以及条件
        String tableNames = "商品编码;盘点数量";

        String checkTableName = array.getJSONArray(0).stream().reduce("", (d1, d2) -> {
            if (d1.equals("")) return d2;
            return d1 + ";" + d2;
        }).toString();

        if (!tableNames.equals(checkTableName))
            throw new RuntimeException("传入数据的格式不正确，请以" + String.join(";", tableNames) + "的顺序传入");

        for (int i = 0, len = array.size(); i < len; i++) {

            if (i == 0) continue; // 跳过表头

            JSONArray tempArray = array.getJSONArray(i);

            Optional<InventoryListItem> anyInventoryList = inventoryLists.stream().filter(inventoryListCompound ->
                    inventoryListCompound.getProductId().getId().equals(tempArray.getString(0))).findAny();
            anyInventoryList.get().setCountQuantity(Double.parseDouble(tempArray.getString(1)));
        }
        return MapUtil.mapper("items", inventoryLists, "msg", "");
    }

    /***
     * 导入数据解析接口
     * 导入盘点差异复盘
     */
    public Map importInventoryDiffCompound(SimpleRequest request) {

        JSONObject importData = request.get("importData"); // excel数据
        JSONObject exclJson = new JSONObject(); //返回值

        JSONArray inventoryDiffCompoundJSONArray = request.getJO().getJSONObject("model").getJSONArray("inventoryDiffCompound");
        List<InventoryDiffCompound> inventoryDiffCompounds = JSON.parseArray(inventoryDiffCompoundJSONArray.toString(), InventoryDiffCompound.class);
        if (importData.keySet().size() != 1) {
            throw new RuntimeException("导入数据不存在或者存在多个工作表");
        }

        // 获取第一个工作表的数据
        String sheetName = (String) importData.keySet().toArray()[0];
        JSONArray array = importData.getJSONArray(sheetName);

        // 判断是否满足表头顺序以及条件
        String tableNames[] = {"商品编码", "复盘数量"};

        String checkTableName = array.getJSONArray(0).stream().reduce("", (d1, d2) -> {
            if (d1.equals("")) return d2;
            return d1 + ";" + d2;
        }).toString();

        if (!String.join(";", tableNames).equals(checkTableName))
            throw new RuntimeException("传入数据的格式不正确，请以" + String.join(";", tableNames) + "的顺序传入");

        for (int i = 0, len = array.size(); i < len; i++) {

            if (i == 0) continue; // 跳过表头

            JSONArray tempArray = array.getJSONArray(i);

            Optional<InventoryDiffCompound> anyInventoryDiffCompound = inventoryDiffCompounds.stream().filter(inventoryDiffCompound ->
                    inventoryDiffCompound.getProductId().getId().equals(tempArray.getString(0))).findAny();
            anyInventoryDiffCompound.get().setCompoundQty(Double.parseDouble(tempArray.getString(1)));
        }
        return MapUtil.mapper("items", inventoryDiffCompounds, "msg", "");
    }
}
